//
// Created by wxd on 2025/7/6.
// 全局的窗口管理
//

#pragma once

#include "../../thirdParty/include/glad/glad.h"
#include "../../thirdParty/include/GLFW/glfw3.h"
#include <memory>
#include <mutex>
#include "../config/config.hpp"
#include "IApplication.h"
#include "../../wrapper/log/Logger.h"
#include <glm/glm.hpp>

// 窗口的配置结构体
struct WindowConfig {
    int m_majorVersion { 3 } ;
    int m_minorVersion { 3 };
    int m_Profile { GLFW_OPENGL_CORE_PROFILE };
    uint32_t m_Width { 800 };
    uint32_t m_Height { 600 };
    const char* m_Title { "OpenGL" };

    void toString() const {
        std::ostringstream oss;
        oss << "majorVersion:" << m_majorVersion << ", "
            << "minorVersion:" << m_minorVersion << ", "
            << "Profile:" << m_Profile << ", "
            << "Width:" << m_Width << ", "
            << "Height:" << m_Height << ", "
            << "Title:" << m_Title << "\n";

        printf("[WindowConfig]: %s", oss.str().c_str());
    }
};

enum class GL_StatusType {
    NONE, INIT, RENDERING, TERMINATE
};


#define EngineApp Application::getInstance()

class Application : public IApplication {
public:
    static Application& getInstance();

    Application(const Application&) = delete;
    Application& operator=(const Application&) = delete;

    ~Application() override;

    /**
     * 默认配置
     */
    void initDefaultWindowConfig(int major = 3, int minor = 3, int profile = GLFW_OPENGL_CORE_PROFILE,
        uint32_t width = 2440, uint32_t height = 2080, const char *title = "OpenGL Rendering Engine") {

        initWindowConfig(major, minor, profile, width, height, title);
    }

    /**
     * 渲染流程相关接口
     */
    void initWindowConfig(int major, int minor, int profile, uint32_t width, uint32_t height, const char *title) override;
    bool init() override;
    bool update() override;
    void destroy() override;

    /**
     * 窗口相关的get
     * @return
     */
    [[nodiscard]] GLFWwindow* getCurrentWindow() const;
    [[nodiscard]] WindowConfig* getWindowConfig() const;
    [[nodiscard]] uint32_t getCurrentWindowWidth() const;
    [[nodiscard]] uint32_t getCurrentWindowHeight() const;
    [[nodiscard]] GL_StatusType getCurrentWindowStatus() const;

    [[nodiscard]] glm::vec4 getCurrentWindowColor() const;
    [[nodiscard]] float getWindowAspectRatio() const;
    void getCurrentCursorPos(double* xpos, double* ypos) const;

    static std::pair<int, int> getDeviceScreenSize();

    /**
     * 事件回調的注冊方法
     */
    void setResizeCallback(const onResizeCallback& callback);
    void setKeyBoardCallback(const onKeyBoardCallback& callback);
    void setMouseCallback(const onMouseCallback& callback);
    void setCursorCallback(const onCursorCallback& callback);
    void setMouseScrollCallback(const onMouseScrollCallback& callback);

    void setHideMouseCursor(bool isHide);

    bool isGLInited() const;

    void setEnableShowImGUI(bool enable) {
        mEnableShowImGUI = enable;
    }

private:
    Application();

    static std::unique_ptr<Application> m_Instance;

    /**
     * 用于线程安全初始化的标志
     */
    static std::once_flag m_Initialized;

    /**
     * 创建单例
     */
    static void create() {
        m_Instance.reset(new Application());
    }

    /**
     * 窗口配置以及对应的窗口对象，OpenGL支持多窗口，一个窗口对应一个配置
     */
    std::unique_ptr<WindowConfig> m_WindowConfig;
    GLFWwindow* m_GLWindow;
    float m_WindowRatio;

    /**
     * 窗口的默认buffer刷新色值
     */
    glm::vec4 m_GLWindowColor;

    /**
     * 当前窗口状态
     */
    GL_StatusType m_WindowStatus;

    /**
     * 窗口当前的事件类型
     */
    static WindowEvent m_WindowEvent;

    /**
     * GLFW事件回调对象
     */
    onResizeCallback m_ResizeCallback;
    onKeyBoardCallback m_KeyBoardCallback;
    onMouseCallback m_MouseCallback;
    onCursorCallback m_CursorCallback;
    onMouseScrollCallback m_MouseScrollCallback;

    /**
     * GLFW提供监听的函数指针类型的具体函数类型
     */
    static void framebufferSizeCallback(GLFWwindow* window, int width, int height);
    static void keyBoardCallback(GLFWwindow* window, int key, int scancode, int action, int mods);
    static void mouseCallback(GLFWwindow* window, int button, int action, int mods);
    static void cursorCallback(GLFWwindow* window, double xPos, double yPos);
    static void mouseScrollCallback(GLFWwindow* window, double xOffset, double yOffset);

    bool m_IsHideMouseCursor { false };

    bool mGLInited { false };

    bool mEnableShowImGUI { false };

    void initImGUI() const;
    void openImGUIRenderFrame() const;
    void renderImGUIFrame() const;
};

